#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>

#include "set.h"
#include "set_errno.h"

static int nb_test = 0;



void test_size() {
  nb_test++;

  struct set* s = set__empty();

  assert(set__size(s) == 0);

  set__add(s, 'e');
  set__add(s, 'o');
  set__add(s, 'a');

  assert(set__size(s) == 3);

  set__add(s, 'a');
  assert(set__size(s) == 3);

  set__add(s, 'x');
  assert(set__size(s) == 4);

  set__remove(s, 'a');
  assert(set__size(s) == 3);

  set__free(s);
}

void test_is_empty ()
{

  nb_test ++;
  struct set* s = set__empty();

  assert(set__is_empty (s) == 1);

  set__add(s, 'a');
  assert (set__is_empty (s) ==0 );

  set__free(s);

}

void test_add() {

  nb_test++;

  struct set* s = set__empty();

  assert(set__add(s, 'x') == 0);

  set__add(s, 'e');
  set__add(s, 'o');
  set__add(s, 'a');

  assert(set__add(s, 'x') == 1);
  assert(set__errno == SET__ELEMENT_DUPLICATION);

  assert(set__find(s, 'a'));
  assert(set__find(s, 'e'));
  assert(set__find(s, 'o'));

  set__free(s);
}

void test_find ()
{
  nb_test ++;
  struct set* s = set__empty();

  assert( set__find( s, 'a' ) == 0) ;

  set__add(s , 'a');
  assert( set__find( s, 'a' ) == 1 );

  set__free(s);
}

void test_remove ()
{
  nb_test ++;
  struct set* s = set__empty();
  struct set* sprime = set__empty();

  set__remove( s, 'a') ;
  assert (set__is_empty (s) == true) ;

  set__add(s, 'b');
  set__add(sprime , 'b');

  set__add(s , 'a') ;
  set__remove(s, 'a');

  assert (set__compare (s, sprime) == 1);

  set__free(s);
  set__free(sprime);
  s =set__empty();
  sprime = set__empty();

  set__add (s , 'a');
  set__remove(s, 'b');

  set__remove (sprime, 'b');
  set__add(sprime , 'a');

  assert( set__compare (s, sprime)==1  );

  set__free(s);
  set__free(sprime);

}



void test_inter() {
  nb_test++;

  struct set* s1  = set__empty();
  struct set* s2  = set__empty();
  struct set* res = set__empty();

  set__add(s2, 'e');
  set__add(s2, 'h');
  set__add(s2, 'o');
  set__add(s2, 'x');

  set__inter(s1, s2, res);
  assert(set__is_empty(res));

  set__add(s1, 'd');
  set__add(s1, 'h');
  set__add(s1, 'm');
  set__add(s1, 'o');

  set__inter(s1, s2, res);
  assert(set__is_empty(res) == false);

  assert(set__size(res) == 2);
  assert(set__find(res, 'o'));
  assert(set__find(res, 'h'));

  set__free(s1);
  set__free(s2);
  set__free(res);
}


void test_union() {
  nb_test++;

  struct set* s1  = set__empty();
  struct set* s2  = set__empty();
  struct set* res = set__empty();

  set__add(s2, 'e');
  set__add(s2, 'h');
  set__add(s2, 'o');
  set__add(s2, 'x');

  set__union(s1, s2, res);
  assert(set__compare(s2, res));

  set__free(s1);
  set__free(res);
  s1 = set__empty() ;
  res = set__empty();
  struct set* s3 = set__empty();
  struct set* s4 = set__empty();
  struct set* res2 = set__empty();
  set__add(s4, 'e');
  set__add(s4, 'h');
  set__add(s4, 'o');
  set__add(s4, 'x');

  set__add(s3 ,'a');
  set__union (s3, s4, res2);

  set__union (s1, s2,  res);
  set__add(res , 'a');

  assert(set__compare(res, res2));

  set__free(s1);
  set__free(s2);
  set__free(s3);
  set__free(s4);
  set__free(res);
  set__free(res2);
}

int main() {
  test_size();
  test_is_empty();

  test_find();
  test_add();
  test_remove();

  test_inter();
  test_union();

  printf("OK(%d)\n", nb_test);
  return EXIT_SUCCESS;
}
